[Java][Spring Boot] DAOを作ってJPQLを操ってみる。
はじめに
Spring BootのMVCの意味を考えると、コントローラーにデータベースにアクセスするコードを書くべきでは無い様です。 DAO(Data Access Object)を使用する事で実現できます。 そこで、これまでの記事の様にEntity、Repository、Service、Controllerではなく、Entity、DAO、Controllerの構成で作ってみます。 また、より低レベルなJPQLへの入り口にも触れてみました。
環境
Mac OSX 10.10.5 Yosemite Eclipse Mars2 Java 8 Spring Boot 1.3.6 PostgreSQL 9.5.1
準備
テーブル:fruit
CREATE TABLE fruit ( id VARCHAR(2) NOT NULL, name VARCHAR(10), price integer, PRIMARY KEY(id) ); INSERT INTO fruit VALUES ('1','apple',300), ('2','orange',200), ('3','banana',100);
postgres=# select * from fruit; id | name | price ----+--------+------- 1 | apple | 300 2 | orange | 200 3 | banana | 100 (3 rows)
コード
build.gradle(依存関係のみ抜粋)
dependencies { compile('org.springframework.boot:spring-boot-starter-data-jpa') compile('org.springframework.boot:spring-boot-starter-jdbc') compile('org.projectlombok:lombok:1.16.6') compile('org.springframework.boot:spring-boot-starter-web') runtime('org.postgresql:postgresql') testCompile('org.springframework.boot:spring-boot-starter-test') }
application.yml(DB接続設定)
spring: datasource: url : jdbc:postgresql://localhost/データベース名 username : XXXXX password : YYYYY driverClassName : org.postgresql.Driver
エンティティ
package com.jpa.mydao; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; import lombok.Data; import lombok.Getter; import lombok.Setter; @Entity @Data @Table(name="fruit") public class Fruit { @Id private String id; private String name; private Integer price; }
11行目、Entity設定 12行目、Lombok。getter/setterを設定する目的。 [Java]Lombokでコードを短縮させる。 13行目、テーブル「fruit」に繋げる設定。
DAOインターフェース
package com.jpa.mydao.dao; import java.io.Serializable; import java.util.List; public interface FruitDao <T> extends Serializable { public List<T> getAll(); public List<T> getWhereId(String id); }
DAOで使用するメソッドを作成。
DAOオブジェクト
package com.jpa.mydao.dao; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query; import org.springframework.stereotype.Repository; import com.jpa.mydao.Fruit; @Repository public class FruitDaoJpql implements FruitDao<Fruit>{ private EntityManager entityManager; public FruitDaoImpl() { super(); } public FruitDaoImpl(EntityManager entityManager) { this.entityManager = entityManager; } @Override public List<Fruit> getAll() { Query query = entityManager.createQuery("from Fruit"); List<Fruit> list = query.getResultList(); entityManager.close(); return list; } @Override public List<Fruit> getWhereId(String id) { List<Fruit> list = entityManager .createQuery("from Fruit where id = :id") .setParameter("id", id) .getResultList(); return list; } }
ここでDAOインターフェースを使用します。 18行目と22行目のコンストラクタはLombokでも良いのですが、ちゃんと書いた方が分かりやすいかなと思いました。 Lombok使用なら、クラスに@AllArgsConstructorと@NoArgsConstructorですね。
26~32行目、DAOインターフェースで作成したメソッド、getAll()。 メソッド名通り、全レコードを取得するように設定します。 28行目、EntityManager.createQuery()でJPQLを作成できます。 "from Fruit"は、SQL"select * from fruit;"と同じ意味です。 注意点すべきはテーブル名で、エンティティに設定したクラス名を指定しましょう。 SQLのように、小文字でテーブルを直に指定しようとすると、QuerySyntaxExceptionが発生します。 29行目、クエリ実行結果をListに入れます。
34~42行目、指定したIDに一致するレコードを取得するメソッド、getWhereId()。 今度はQueryをショートカットして実行結果をListに入れています。 38~39行目、getAll()とはJPQLが違いパラメータidを設定するので、 setParameter("キー", パラメータ)と設定し、JPQLクエリに「:キー」と設定してパラメータを参照させます。
コントローラー
package com.jpa.mydao; import java.util.List; import javax.annotation.PostConstruct; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.jpa.mydao.dao.FruitDaoJpql; @RestController public class EntityManagerController { @PersistenceContext EntityManager entityManager; FruitDaoJpql dao; @PostConstruct public void init() { dao = new FruitDaoJpql(entityManager); } @RequestMapping(value="/all", method=RequestMethod.GET) public List<Fruit> all() { List<Fruit> list = dao.getAll(); return list; } @RequestMapping(value="/where", method=RequestMethod.GET) public List<Fruit> where(@RequestParam("id") String id) { List<Fruit> list = dao.getWhereId(id); return list; } }
17行目、@RestControllerを設定。 ターミナルからcurlコマンドで取得結果を表示して確認するためです。
20~21行目、@PersistenceContextでアプリ起動時にBeanに登録されるEntityManagerを結びつけています。 EntityManagerは1つのアプリで1度しか設定できず、複数設定するとエラーとなります。
25~28行目、@PostConsructでコンストラクタ実行後に自動的に呼ばれるメソッドを作り、DAOオブジェクトにEntityManagerを渡します。 これは、残り2つのメソッドを使用するための準備だと思ってください。
30~34行目、メソッドall()。 FruitDaoJpql.getAll()で、テーブルfruitの全レコードを取得し、Listを返します。 その返し値をreturnに指定。
36~40行目、メソッドwhere()。 FruitDaoJpql.getWhereId()の引数にidを渡して、対象のレコードを取得し、Listを返します。 返し値をreturnに指定。
ターミナルから実行
all()
$ curl http://localhost:8080/all [{"id":"1","name":"apple","price":300},{"id":"2","name":"orange","price":200},{"id":"3","name":"banana","price":100}]
where()
$ curl http://localhost:8080/where?id=1 [{"id":"1","name":"apple","price":300}]
さいごに
これでコードがシンプルになるのでは無いでしょうか。 今度はJPQLについて、さらに深く掘ってみようと思います。